package com.lagou.sqlsession;

import com.lagou.config.Configuration;
import com.lagou.config.MapperStatement;
import com.lagou.execute.Execute;
import com.lagou.execute.SimpleExecute;

import java.lang.reflect.*;
import java.sql.SQLException;
import java.util.List;

/**
 * Created by seemygo on 2020/11/13.
 */
public class DefaultSqlSession implements SqlSession {
    private Configuration configuration;

    public DefaultSqlSession(Configuration configuration) {
        this.configuration = configuration;
    }
    //Execute对象定义处理方式
    Execute simpleExecute=new SimpleExecute();
    /**
     * 查询所有用户信息
     * @param statementId
     * @param params
     * @return
     */
    public <E>List<E> queryAll(String statementId,Object... params) throws Exception {
        //获取statementId
        MapperStatement mapperStatement=configuration.getMapperStatementMap().get(statementId);
        List<E> objects = simpleExecute.query(configuration, mapperStatement, params);
        return objects;
    }

    /**
     * 查询单个用户数据
     * @param statementId
     * @param params
     * @return
     */
    public <T>T queryOne(String statementId, Object... params) throws Exception {
        List<Object> objects = queryAll(statementId, params);
        if(objects.size()==1){
           return (T) objects.get(0);
        }else{
            throw new RuntimeException("返回结果过多！");
        }
    }

    /**
     * 新增 修改  删除
     * @param statementId
     * @param params
     */
    public void execute(String statementId, Object... params) throws Exception {
        MapperStatement mapperStatement = configuration.getMapperStatementMap().get(statementId);
        simpleExecute.execute(configuration, mapperStatement, params);
    }

    /**
     * 实现jdk动态代理 基于mapper接口
     * @param mapperClass
     * @param <T>
     * @return
     */
    public <T> T getMapper(Class<T> mapperClass) {
        T o = (T)Proxy.newProxyInstance(mapperClass.getClassLoader(), new Class[]{mapperClass}, new InvocationHandler() {
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                //这里proxy表示代理对象
                //method表示代理对象调用的方法
                //args表示方法的参数
                //限制一   方法名 限制Mapper.xml中方法的id和调用的方法名同名
                String name = method.getName();
                //限制二  获取全限定类名  用来规定mapper.xml的namespace的全限定类名
                String className = method.getDeclaringClass().getName();
                //statementId
                String statementId = className + "." + name;
                MapperStatement mapperStatement = configuration.getMapperStatementMap().get(statementId);
                Type genericReturnType = method.getGenericReturnType();
                //是否泛型实例化
                if(genericReturnType instanceof ParameterizedType){
                    //如果返回类型含有泛型
                    return queryAll(statementId,args);
                }
                if(genericReturnType.equals(Void.TYPE)){
                    execute(statementId,args);
                    return null;
                }
                return queryOne(statementId,args);
            }
        });
        return o;
    }



}
